/**
*  \file AnalogInput.c
*
*  \brief
*
*  \author Dajin Li
*
*
*/
/*===============================================[ private includes  ]================================================*/
#include "stm32f10x.h"
#include "global.h"
#include "analoginput.h"
#include "var_tbl.h"
#include "pwm.h"


/*===============================================[ private defines   ]================================================*/
#define AD1_ADC_RANK                           1
#define UPA1_ADC_CHNL                          2
#define UPA2_ADC_CHNL                          3
#define UPA3_ADC_CHNL                          1
#define FUEL_ADC_CHNL                          4
#define TEMP_ADC_CHNL                          5
#define VDD_ADC_CHNL                           6
#define TC_ADC_CHNL                            7
#define MAST_ADC_CHNL                          8

#define ADC_SAMPLE_CNT     		               32
#define ADC_SAMPLE_NUMBER                      1
#define ADC_BUFFER_DEEP                        32

#define UNDER_VOLTAGE_DELAY                    100
#define OVER_VOLTAGE_DELAY                     100

/*===============================================[ private datatypes ]================================================*/

/*===============================================[ private variables ]================================================*/
static s16 adc_samples_times = 0;
static s16 ad1_adc[ADC_BUFFER_DEEP] = {0};
static __IO u16 AD_Result_Value[ADC_SAMPLE_NUMBER] = {0};
u16 ad_value[4];

/*===============================================[ public variables  ]================================================*/
s16 upa1_adc_value = 0;
s16 upa2_adc_value = 0;
s16 upa3_adc_value = 0;
s16 fuel_adc_value = 0;
s16 temp_adc_value = 0;
s16 vdd_adc_value = 0;
s16 distance_reverse = 0;
s16 tc_temp_adc_value = 0;
s16 mast_adc_value = 0;
s32 Vbat_temp = 0;
u8 adc_ready = 0;
s32 Vbat_filter = 0;

s16 upa1_adc_value_kwp = 0;
s16 upa2_adc_value_kwp = 0;
s16 upa3_adc_value_kwp = 0;
s16 fuel_adc_value_kwp = 0;
s16 temp_adc_value_kwp = 0;
s16 tc_temp_adc_value_kwp = 0;
s16 mast_adc_value_kwp = 0;
u16 reverse_buzzer_on = 0;
u16 min_revser_value = 0;
u8 buzzer_type = 0;
u8 reverse_logic = 0;
s16 ad1_adc_value = 0;
/*===============================================[ inline functions ]=================================================*/
/*===============================================[ private functions ]================================================*/
static void ADC_SlidingWindow(s16 *buffer, s16 length);
static s16 ADC_Average(s16 *buffer, s16 length);
static s16 ADC_Average(s16 *buffer, s16 length);

/*===============================================[ public functions ]=================================================*/

/**
* @brief	Initializes A/D converter.
* @param	none
* @note     none
* @retval   none
*/
void AnalogInputs_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	
    
    /*Config PC4 as ADC1 input chanel 4*/
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;		                  
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
    
    DMA_DeInit(DMA1_Channel1);                                                    //Reset DMA chanel1
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)( &(ADC1->DR));               //DMA periphera base address point to adc1 base address
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Result_Value;                 //DMA memory base point to adc value memory
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                            //DMA Direction peripheral device to memory: ADC1 value -> AD_Result_Value
    DMA_InitStructure.DMA_BufferSize = ADC_SAMPLE_NUMBER;                         //ADC sample buffer size
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;              //Peripheral device not increase
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                       //Memory increase
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   //DMA Data size 16bits
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;          //Memory data size 16bits
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                               //DMA mode: loop mode
    DMA_InitStructure.DMA_Priority = DMA_Priority_High ;                          
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                  //Disable memory to DMA
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                  //Init DMA Chanel 1
	DMA_Cmd(DMA1_Channel1,ENABLE);
    
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                            //ADC independent mode
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                  //Scan mode enable
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                           //Continuous Convert Mode disable
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;           //External trig none
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                        //Data align right
	ADC_InitStructure.ADC_NbrOfChannel = ADC_SAMPLE_NUMBER;                       //ADC sample chanel 1
    ADC_Init(ADC1, &ADC_InitStructure);
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);                                             //Config adc clock, PLCK div8: 9MHz
    ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_13Cycles5);  //ADC sample time, 13.5 cycles
	ADC_DMACmd(ADC1,ENABLE);
	ADC_Cmd(ADC1,ENABLE);
    
    ADC_ResetCalibration(ADC1);                                                   //ADC1 Reset Calibration
	while(ADC_GetResetCalibrationStatus(ADC1))
    {
        ;
    }                                                                             //Wait ADC1 Reset Calibration finish
    
    ADC_StartCalibration(ADC1);                                                   //Start calibration
	while(ADC_GetCalibrationStatus(ADC1))
    {
        ;     
    }                                                                             //Wait ADC1 calibration finish
    
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                                       //Enable software trig mode
    ADSample_Timer3_Init();
}
/**
* @brief	This samples the analog inputs.
* @param	none
* @note     none
* @retval   none
*/

void analog_inputs_task(void const *argument) 
{
    // Initialization 
    task_status[SAMPLE_ANALOG_INPUTS_ID] = ALIVE;
    // Tasks must run in an infinite loop:
    while (TRUE)
    {
        if(adc_samples_times < ADC_SAMPLE_CNT)
        {
            adc_samples_times++;
        }
        else
        {
            ADC_SlidingWindow(ad1_adc, ADC_SAMPLE_CNT);
        }

        ad1_adc[adc_samples_times - 1] = AD_Result_Value[AD1_ADC_RANK - 1];

        if(adc_samples_times >= ADC_SAMPLE_CNT)	
        {
            ad1_adc_value = ADC_Average(ad1_adc, ADC_SAMPLE_CNT);
        }
        task_status[SAMPLE_ANALOG_INPUTS_ID] = ALIVE;
        osDelay(SAMPLE_ANALOG_INPUTS_ITV);
    }  // end while infinite loop
}  // end task_sample_sw_inputs()	

/*===============================================[ private functions ]================================================*/

static void ADC_SlidingWindow(s16 *buffer, s16 length)
{
    int i;

    for(i = 0; i < length - 1; i++)
    {
        buffer[i] = buffer[i+1];
    }
}

static s16 ADC_Average(s16 *buffer, s16 length)
{
    int i;
    s32 total = 0;

    for(i = 0; i < length; i++)
    {
        total += buffer[i];
    }

    total = total/length;
    return total;
}
/***********************************************************************************************************************
*                             Copyright 2016 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/
 
